package org.jeecg.modules.xxlJob;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jeecg.dingtalk.api.base.JdtBaseAPI;
import com.jeecg.dingtalk.api.core.vo.AccessToken;
import com.jeecg.dingtalk.api.message.JdtMessageAPI;
import com.jeecg.dingtalk.api.message.vo.Message;
import com.jeecg.dingtalk.api.message.vo.TextMessage;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.htmlcleaner.CleanerProperties;
import org.htmlcleaner.HtmlCleaner;
import org.jeecg.common.api.dto.message.MessageDTO;
import org.jeecg.common.config.mqtoken.UserTokenContext;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.api.model.TimingLog;
import org.jeecg.common.system.api.model.TimingOperate;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.*;
import org.jeecg.config.thirdapp.ThirdAppConfig;
import org.jeecg.modules.message.handle.impl.EmailSendMsgHandle;
import org.jeecg.modules.system.controller.ThirdAppController;
import org.jeecg.modules.system.entity.SysThirdAccount;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysThirdAccountService;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.system.service.ITimingLogService;
import org.jeecg.modules.system.service.ITimingOperateService;
import org.jeecg.modules.system.service.impl.ThirdAppDingtalkServiceImpl;
import org.jeecg.common.system.api.model.XxlSendDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
public class XxlJobSend {
    
    @Autowired
    ISysBaseAPI sysBaseAPI;
    
    @Autowired
    ISysUserService sysUserService;
    
    @Autowired
    ThirdAppController thirdAppController;
    
    @Autowired
    ThirdAppConfig thirdAppConfig;
    
    @Autowired
    ThirdAppDingtalkServiceImpl dingtalkService;
    
    @Autowired
    ITimingOperateService timingOperateService;
    
    @Autowired
    ITimingLogService timingLogService;
    
    @Autowired
    private ISysThirdAccountService sysThirdAccountService;
    
    public final String THIRD_TYPE = ThirdAppConfig.DINGTALK.toLowerCase();
    
    public final long SEND_COUNT = 3;
    
    
    @XxlJob("sendMessage")
    public ReturnT<String> sendMessage(String param) {
        //应该吧消息的处理，全部放在配置的url接口中，这样就不用改动定时任务接口，改动url即可，但现在由于没有生成代码，就只能放在这里
        log.info("开始执行消息消息发送定时任务");
        //首先读取业务操作表数据，将所有启用的数据拿出来
        List<TimingOperate> list = timingOperateService.getToAndTcAll();
        for (TimingOperate timingOperate : list) {
            
            //根据操作数据，进行for循环，通过操作表配置id获取配置数据，根据其中的url获取数据，
            String configSourceUrl = timingOperate.getConfigSourceUrl()+ "?messageTemplateCode="+timingOperate.getMessageTemplateCode()+"&noticeDay="+timingOperate.getNoticeTime();
            try {
                UserTokenContext.setToken(getTemporaryToken());
                // 把字符串转换为URL请求地址
                URL url = new URL(configSourceUrl);
                // 打开连接
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                //添加临时token
                connection.setRequestProperty("X-Access-Token", getTemporaryToken());
                // 连接会话
                connection.connect();
                // 获取输入流
                BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line;
                StringBuilder sb = new StringBuilder();
                
                while ((line = br.readLine()) != null) {
                    sb.append(line);
                }
                Map<String, Object> map = (Map<String, Object>) JSON.parseObject(String.valueOf(sb), HashMap.class).get("result");
                br.close();// 关闭流
                connection.disconnect();// 断开连接
                UserTokenContext.remove();
                
                List<XxlSendDto> dtos = JSON.parseArray(JSON.toJSONString(map.get("msgs")), XxlSendDto.class);
                List<String> people = Arrays.asList(timingOperate.getNoticePeople().split(","));;
                //如果获得的数据为空，则不记性消息的发送
                if(dtos.size() > 0){
    
                    String noticeWay = timingOperate.getNoticeWay();
                    for (XxlSendDto xxlSendDto : dtos) {
                        //消息模板参数：必须固定，我想不到动态获取模板参数的方法
                        String title = xxlSendDto.getTitles();
                        String content = xxlSendDto.getContents();
                        String smsCode = timingOperate.getSmsCode();
                        String id = xxlSendDto.getId();
                        for (String user : people) {
                            //如果发送消息类型是系统通知，走通知发送
                            if (noticeWay.contains("system")) {
                                //判断次数，是否发送
                                if(this.sendCount(id, user, timingOperate.getNoticeTime(), "system")){
                                    //系统通知
                                    MessageDTO messageDTO = new MessageDTO("管理员", user, title, content);
                                    sysBaseAPI.sendSysAnnouncement(messageDTO);
                                    log.info("定时任务发送系统");
                                    //添加日志
                                    this.saveLog(title, id, user, "system", timingOperate.getModelName());
                                }
                            }
                            if (noticeWay.contains("dingTlak")) {
                                //判断次数，是否发送
                                if (this.sendCount(id, user, timingOperate.getNoticeTime(), "dingTlak")) {
                                    //钉钉通知
                                    String appKey = thirdAppConfig.getDingtalk().getClientId();
                                    String appSecret = thirdAppConfig.getDingtalk().getClientSecret();
                                    AccessToken accessToken = JdtBaseAPI.getAccessToken(appKey, appSecret);
                                    String access_token = accessToken.getAccessToken();
                                    String[] toUsers = {user};
                                    // 消息内容
                                    int agentId = thirdAppConfig.getDingtalk().getAgentIdInt();
                                    CleanerProperties props = new CleanerProperties();
                                    content = new HtmlCleaner(props).clean(content).getText().toString();
                                    Message<TextMessage> textMessage = new Message<>(agentId, new TextMessage(content));
                                    List<SysThirdAccount> thirdAccountList = sysThirdAccountService.listThirdUserIdByUsername(toUsers, THIRD_TYPE);
                                    List<String> dtUserIds = thirdAccountList.stream().map(SysThirdAccount::getThirdUserId).collect(Collectors.toList());
                                    textMessage.setUserid_list(dtUserIds);
                                    JdtMessageAPI.sendTextMessage(textMessage, access_token);
                                    log.info("定时任务发送钉钉");
                                    //卡片发送，必须有标题和url或者按钮
//                                    Map<String, String> params = xxlSendDto.getParam();
//                                    CleanerProperties props = new CleanerProperties();
//                                    String result = new HtmlCleaner(props).clean(content).getText().toString();
//                                    int agentId = thirdAppConfig.getDingtalk().getAgentIdInt();
//                                    ActionCardMessage message = new ActionCardMessage(result);
//                                    message.setTitle(title);
//                                    if (ObjectUtil.isNotEmpty(params.get("url"))) {
//                                        message.setSingle_title(title);
//                                        message.setSingle_url(params.get("url"));
//                                    }
//                                    Message<ActionCardMessage> actionCardMessage = new Message<>(agentId, message);
//                                    List<SysThirdAccount> thirdAccountList = sysThirdAccountService.listThirdUserIdByUsername(toUsers, THIRD_TYPE);
//                                    List<String> dtUserIds = thirdAccountList.stream().map(SysThirdAccount::getThirdUserId).collect(Collectors.toList());
//                                    actionCardMessage.setUserid_list(dtUserIds);
//                                    JdtMessageAPI.sendActionCardMessage(actionCardMessage, access_token);
    
                                    //添加日志
                                    this.saveLog(title, id, user, "dingTlak", timingOperate.getModelName());
                                }
                            }
                            if (noticeWay.contains("sms")) {
                                if(this.sendCount(id, user, timingOperate.getNoticeTime(), "sms")){
                                    //短信通知,先在DySmsEnum里面添加，之后再用
                                    SysUser sysUser = sysUserService.getUserByName(user);
                                    JSONObject js = JSONObject.parseObject(JSON.toJSONString(xxlSendDto.getParam()));
                                    DySmsEnum dySmsEnum = DySmsEnum.toEnum(smsCode);
                                    DySmsHelper.sendSms(sysUser.getPhone(), js, dySmsEnum);
                                    log.info("定时任务发送短信");
                                    //添加日志
                                    this.saveLog(title, id, user, "sms", timingOperate.getModelName());
                                }
                            }
                            if (noticeWay.contains("email")) {
                                //判断次数，是否发送
                                if(this.sendCount(id, user, timingOperate.getNoticeTime(), "email")){
                                    //邮件通知
                                    SysUser sysUser = sysUserService.getUserByName(user);
                                    EmailSendMsgHandle emailSendMsgHandle = new EmailSendMsgHandle();
                                    emailSendMsgHandle.sendMsg(sysUser.getEmail(), title, content);
                                    log.info("定时任务发送邮件");
                                    //添加日志
                                    this.saveLog(title, id, user, "email", timingOperate.getModelName());
                                }
                            }
                        }
                    }
                }
                
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("失败!");
            }
            
        }
        return ReturnT.SUCCESS;
    }
    
    public static String getTemporaryToken() {
        RedisUtil redisUtil = SpringContextUtils.getBean(RedisUtil.class);
        // 模拟登录生成Token
        String token = JwtUtil.sign("admin", "cb362cfeefbf3d8d");
        // 设置Token缓存有效时间为 5 分钟
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, 5 * 60 * 1000);
        return token;
    }
    
    /**
     * 判断该消息是否已经超过了发送次数，超过就不发送
     * @param id
     * @param username
     * @param noticeDay
     * @param type
     * @return
     */
    public boolean sendCount(String id, String username, int noticeDay, String type){
        boolean flag = true;
        LambdaQueryWrapper<TimingLog> queryWrapper = new LambdaQueryWrapper<>();
        String expiredDay = DateUtil.format(getDay(new Date(), noticeDay), "yyyy-MM-dd HH:mm:ss");
        queryWrapper.gt(TimingLog :: getNoticeTime, expiredDay);
        queryWrapper.lt(TimingLog :: getNoticeTime, new Date());
        queryWrapper.eq(TimingLog :: getNoticeId, id);
        queryWrapper.eq(TimingLog :: getUsername, username);
        queryWrapper.eq(TimingLog :: getNoticeWay, type);
        
        long count = timingLogService.count(queryWrapper);
        if(count >=SEND_COUNT){
            flag = false;
        }
        
        return flag;
    }
    
    /**
     * 获取当前时间day天之前的时间
     * @param date
     * @param day
     * @return
     */
    public Date getDay(Date date, int day){
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - day);
        return calendar.getTime();
    }
    
    /**
     *
     * 保存发送消息日志
     * @param title
     * @param id
     * @param username
     * @param noticeWay
     * @param modelName
     */
    public void saveLog(String title, String id, String username, String noticeWay, String modelName){
        TimingLog timingLog = new TimingLog();
        timingLog.setNoticeTitle(title);
        timingLog.setNoticeId(id);
        timingLog.setUsername(username);
        timingLog.setNoticeWay(noticeWay);
        timingLog.setModelName(modelName);
        timingLog.setNoticeTime(new Date());
        timingLog.setCreateTime(new Date());
        timingLog.setCreateBy("admin");
        timingLogService.save(timingLog);
    
    }
    
}
